﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Caching;

namespace Empires.CRL.Tools
{
    /// <summary>
    /// 该缓存类存在一定问题，为乐保护线程安全，避免重复插入，使用了锁。这样一来会导致吞吐量下降
    /// </summary>
    public class DefaultCacheStrategy
    {
        private static DefaultCacheStrategy instance = null;

        protected static volatile System.Web.Caching.Cache webCache = System.Web.HttpRuntime.Cache;

        private static object syncObj = new object();

        protected System.Web.Caching.Cache WebCache
        {
            get
            {
                if (webCache != null)
                { return webCache; }
                return null;
            }
        }

        public static DefaultCacheStrategy GetEntity()
        {
            if (instance == null)
            {
                lock (syncObj)
                {
                    if (instance == null)
                    {
                        instance = new DefaultCacheStrategy();
                    }
                }
            }
            return instance;
        }

        //private void RemoveCacheCallBack(string objID, object objValue, System.Web.Caching.CacheItemRemovedReason reason)
        //{
        //    switch (reason)
        //    {
        //        case System.Web.Caching.CacheItemRemovedReason.DependencyChanged:
        //            //因为依赖改变而删除
        //            break;
        //        case System.Web.Caching.CacheItemRemovedReason.Expired:
        //            //因为超时而删除
        //            break;
        //        case System.Web.Caching.CacheItemRemovedReason.Removed:
        //            //因为主动调用了删除而删除
        //            break;
        //        case System.Web.Caching.CacheItemRemovedReason.Underused:
        //            //为了释放内存而删除
        //            break;
        //        default:
        //            break;
        //    }
        //}

        #region ICacheStrategy 成员

        public void AddObjectWithNoExpired(string objId, object o, Action<string, object> RemoveCallBack, Action<string, object> UnderusedCallBack)
        {
            if (webCache != null)
            {
                webCache.Insert(objId,
                    o,
                    null,
                    System.Web.Caching.Cache.NoAbsoluteExpiration,
                    System.Web.Caching.Cache.NoSlidingExpiration,
                    CacheItemPriority.BelowNormal,
                    (key, value, reason) =>
                    {
                        switch (reason)
                        {
                            case CacheItemRemovedReason.Removed:
                                if (RemoveCallBack != null)
                                {
                                    RemoveCallBack.Invoke(key, value);
                                }
                                break;
                            case CacheItemRemovedReason.Underused:
                                if (UnderusedCallBack != null)
                                {
                                    UnderusedCallBack.Invoke(key, value);
                                }
                                break;
                        }
                    });
            }
        }

        public void AddObjectWithAbsoluteTime(string objId, object o, int absoluteTime, System.Web.Caching.CacheItemPriority priority)
        {
            if (absoluteTime > 0 && webCache != null)
            {
                if (!String.IsNullOrEmpty(objId) && o != null)
                {
                    var cut = webCache.Get(objId);
                    if (cut == null)
                    {
                        lock (syncObj)
                        {
                            if (cut == null)
                            {
                                webCache.Insert(objId
                                    , o
                                    , null
                                    , DateTime.Now.AddMilliseconds(absoluteTime)
                                    , System.Web.Caching.Cache.NoSlidingExpiration
                                    , priority
                                    , null);
                            }
                        }
                    }
                }
            }
        }
        public void AddObjectWithAbsoluteTime(string objId, object o, int absoluteTime, System.Web.Caching.CacheItemPriority priority, CacheItemRemovedCallback target)
        {
            if (absoluteTime > 0 && webCache != null)
            {
                if (!String.IsNullOrEmpty(objId) && o != null)
                {
                    var cut = webCache.Get(objId);
                    if (cut == null)
                    {
                        lock (syncObj)
                        {
                            if (cut == null)
                            {
                                webCache.Insert(objId
                                    , o
                                    , null
                                    , DateTime.Now.AddMilliseconds(absoluteTime)
                                    , System.Web.Caching.Cache.NoSlidingExpiration
                                    , priority
                                    , target);
                            }
                        }
                    }
                }
            }
        }

        public void AddObjectWithSlidingTime(string objId, object o, int slidingTime, System.Web.Caching.CacheItemPriority priority)
        {
            if (slidingTime > 0 && webCache != null)
            {
                if (!String.IsNullOrEmpty(objId) && o != null)
                {
                    var cut = webCache.Get(objId);
                    if (cut == null)
                    {
                        lock (syncObj)
                        {
                            if (cut == null)
                            {
                                webCache.Insert(objId
                                    , o
                                    , null
                                    , DateTime.MaxValue
                                    , TimeSpan.FromMilliseconds(slidingTime)
                                    , priority
                                    , null);
                            }
                        }
                    }
                }
            }
        }
        public void AddObjectWithSlidingTime(string objId, object o, int slidingTime, System.Web.Caching.CacheItemPriority priority, CacheItemRemovedCallback target)
        {
            if (slidingTime > 0 && webCache != null)
            {
                if (!String.IsNullOrEmpty(objId) && o != null)
                {
                    var cut = webCache.Get(objId);
                    if (cut == null)
                    {
                        lock (syncObj)
                        {
                            if (cut == null)
                            {
                                webCache.Insert(objId
                                    , o
                                    , null
                                    , DateTime.MaxValue
                                    , TimeSpan.FromMilliseconds(slidingTime)
                                    , priority
                                    , target);
                            }
                        }
                    }
                }
            }
        }

        public void AddObjectWithDepend(string objId, object o, CacheDependency[] deps, TimeOutBy by, int timeOut, System.Web.Caching.CacheItemPriority priority)
        {
            if (!String.IsNullOrEmpty(objId) && o != null && deps.Length > 0)
            {
                AggregateCacheDependency aggdep = new AggregateCacheDependency();
                aggdep.Add(deps);
                  var cut = webCache.Get(objId);
                  if (cut == null)
                  {
                      lock (syncObj)
                      {
                          if (cut == null)
                          {
                              if (by == TimeOutBy.AbsoluteTime)
                              {
                                  webCache.Insert(objId, o
                                      , aggdep
                                      , DateTime.Now.AddMilliseconds(timeOut)
                                      , System.Web.Caching.Cache.NoSlidingExpiration
                                      , priority
                                      , null);

                              }
                              else if (by == TimeOutBy.SlidingTime)
                              {
                                  webCache.Insert(objId, o
                                      , aggdep
                                      , System.Web.Caching.Cache.NoAbsoluteExpiration
                                      , TimeSpan.FromMilliseconds(timeOut)
                                      , priority
                                      , null);
                              }
                              else
                              {
                                  webCache.Insert(objId, o
                                      , aggdep
                                      , System.Web.Caching.Cache.NoAbsoluteExpiration
                                      , System.Web.Caching.Cache.NoSlidingExpiration
                                      , priority
                                      , null);
                              }
                          }
                      }
                  }
            }
        }
        public void AddObjectWithDepend(string objId, object o, CacheDependency[] deps, TimeOutBy by, int timeOut, System.Web.Caching.CacheItemPriority priority, CacheItemRemovedCallback target)
        {
            if (!String.IsNullOrEmpty(objId) && o != null && deps.Length > 0)
            {
                AggregateCacheDependency aggdep = new AggregateCacheDependency();
                aggdep.Add(deps);
                var cut = webCache.Get(objId);
                if (cut == null)
                {
                    lock (syncObj)
                    {
                        if (cut == null)
                        {
                            if (by == TimeOutBy.AbsoluteTime)
                            {
                                webCache.Insert(objId, o
                                    , aggdep
                                    , DateTime.Now.AddMilliseconds(timeOut)
                                    , System.Web.Caching.Cache.NoSlidingExpiration
                                    , priority
                                    , target);

                            }
                            else if (by == TimeOutBy.SlidingTime)
                            {
                                webCache.Insert(objId, o
                                    , aggdep
                                    , System.Web.Caching.Cache.NoAbsoluteExpiration
                                    , TimeSpan.FromMilliseconds(timeOut)
                                    , priority
                                    , target);
                            }
                            else
                            {
                                webCache.Insert(objId, o
                                    , aggdep
                                    , System.Web.Caching.Cache.NoAbsoluteExpiration
                                    , System.Web.Caching.Cache.NoSlidingExpiration
                                    , priority
                                    , target);
                            }
                        }
                    }
                }
            }
        }
        public void RemoveObject(string objId)
        {
            if (!String.IsNullOrEmpty(objId))
            {
                object o = webCache.Get(objId);
                if (o != null)
                {
                    webCache.Remove(objId);
                }
            }
        }

        public object RetrieveObject(string objId)
        {
            if (!String.IsNullOrEmpty(objId))
            {
                object o = webCache.Get(objId);
                if (o != null)
                {
                    return o;
                }
            }
            return null;
        }

        public enum TimeOutBy
        {
            SlidingTime, AbsoluteTime, NoTimeOut
        }
        #endregion
    }
}
